from typing import Dict, List, Optional
from datetime import datetime
import pandas as pd
from abc import ABC, abstractmethod
from dataclasses import dataclass
from portfolio_trader.advisor.data_class import AdviceData, AccountData, PositionData, Decision

@dataclass
class AccountData:
    """账户数据结构"""
    total_asset: float = 0.0      # 总资产
    market_value: float = 0.0     # 总市值
    available: float = 0.0        # 可用资金
    daily_pnl: float = 0.0       # 当日盈亏

@dataclass
class PositionData:
    """持仓数据结构"""
    volume: int = 0              # 总持仓
    available: int = 0           # 可用持仓
    cost: float = 0.0           # 成本价
    current_price: float = 0.0   # 现价
    market_value: float = 0.0    # 市值
    pnl: float = 0.0            # 盈亏金额
    pnl_pct: float = 0.0        # 盈亏百分比
    daily_pnl: float = 0.0      # 当日盈亏
    daily_pnl_pct: float = 0.0  # 当日盈亏百分比
    name: str = ""              # 股票简称
    exchange: str = ""          # 交易所

@dataclass
class AdviceData:
    """投资建议数据结构"""
    datetime: datetime
    advisor_name: str
    decisions: List[Decision]
    formatted_advice: str
    raw_data: Dict

class AdvisorTemplate(ABC):
    """投资建议生成器模板"""
    
    @abstractmethod
    def on_init(self):
        """初始化"""
        pass
        
    @abstractmethod
    def on_data(self, data: Dict):
        """数据更新回调"""
        pass
        
    @abstractmethod
    def generate_advice(self) -> Dict:
        """生成投资建议"""
        pass
        
    @abstractmethod
    def get_parameters(self) -> Dict:
        """获取参数"""
        pass
        
    @abstractmethod
    def set_parameters(self, params: Dict):
        """设置参数"""
        pass

class AdvisorEngine:
    """投资建议引擎"""
    
    def __init__(self):
        self.advisors: Dict[str, AdvisorTemplate] = {}
        self.advice_history: List[AdviceData] = []
        self._market_data: Optional[pd.DataFrame] = None
        self._account: AccountData = AccountData()
        self._positions: Dict[str, PositionData] = {}
        
    def add_advisor(self, name: str, strategy_name: str, initial_capital: float):
        """添加投资建议生成器"""
        advisor = AdvisorTemplate()
        advisor.on_init()
        self.advisors[name] = advisor
        
    def remove_advisor(self, name: str):
        """移除投资建议生成器"""
        if name in self.advisors:
            del self.advisors[name]
            
    def update_market_data(self, data: pd.DataFrame):
        """更新市场数据"""
        from .data_utils import validate_market_data
        
        if not validate_market_data(data):
            raise ValueError("Invalid market data format")
            
        self._market_data = data
        for advisor in self.advisors.values():
            advisor.on_data(data.to_dict())
            
    def update_account(self, account: Dict[str, float], positions: Dict[str, Dict]):
        """更新账户信息
        
        Args:
            account: 账户信息字典，包含total_asset/market_value/available/daily_pnl
            positions: 持仓信息字典，格式为{symbol: position_dict}
        """
        # 更新账户信息
        self._account = AccountData(
            total_asset=account["total_asset"],
            market_value=account["market_value"],
            available=account["available"],
            daily_pnl=account["daily_pnl"]
        )
        
        # 更新持仓信息
        self._positions.clear()
        for symbol, pos_dict in positions.items():
            self._positions[symbol] = PositionData(
                volume=pos_dict["volume"],
                available=pos_dict["available"],
                cost=pos_dict["cost"],
                current_price=pos_dict["current_price"],
                market_value=pos_dict["market_value"],
                pnl=pos_dict["pnl"],
                pnl_pct=pos_dict["pnl_pct"],
                daily_pnl=pos_dict["daily_pnl"],
                daily_pnl_pct=pos_dict["daily_pnl_pct"],
                name=pos_dict.get("name", ""),
                exchange=pos_dict.get("exchange", "")
            )
        
        # 更新所有advisor的账户信息
        for advisor in self.advisors.values():
            advisor.on_data({
                "account": self._account.__dict__,
                "positions": {k: v.__dict__ for k, v in self._positions.items()}
            })
            
    def get_advice(self, name: str) -> Optional[AdviceData]:
        """获取投资建议"""
        if name not in self.advisors:
            return None
            
        advisor = self.advisors[name]
        decisions = advisor.generate_advice()
        formatted_advice = advisor.format_advice(decisions)
        
        advice_data = AdviceData(
            datetime=datetime.now(),
            advisor_name=name,
            decisions=decisions,
            formatted_advice=formatted_advice,
            raw_data={
                "market_data": self._market_data.to_dict() if self._market_data is not None else None,
                "account": self._account.__dict__,
                "positions": {k: v.__dict__ for k, v in self._positions.items()}
            }
        )
        
        self.advice_history.append(advice_data)
        return advice_data
        
    def get_history(self, 
                   start: Optional[datetime] = None, 
                   end: Optional[datetime] = None,
                   advisor_name: Optional[str] = None) -> List[AdviceData]:
        """获取历史建议
        
        Args:
            start: 开始时间
            end: 结束时间
            advisor_name: 顾问名称筛选
            
        Returns:
            List[AdviceData]: 历史建议列表
        """
        filtered_history = self.advice_history
        
        if start:
            filtered_history = [h for h in filtered_history if h.datetime >= start]
        if end:
            filtered_history = [h for h in filtered_history if h.datetime <= end]
        if advisor_name:
            filtered_history = [h for h in filtered_history if h.advisor_name == advisor_name]
            
        return filtered_history
    
    def get_advisor_parameters(self, name: str) -> Dict:
        """获取顾问参数
        
        Args:
            name: 顾问名称
            
        Returns:
            Dict: 参数字典
        """
        if name in self.advisors:
            return self.advisors[name].get_parameters()
        return {}
    
    def set_advisor_parameters(self, name: str, params: Dict):
        """设置顾问参数
        
        Args:
            name: 顾问名称
            params: 参数字典
        """
        if name in self.advisors:
            self.advisors[name].set_parameters(params) 